package service

import (
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/pkg/errors"
	"io"
	"mime/multipart"
	"os"
	"path"
	"sensi/common/sys"
)

const (
	FileDir = "./uploads"
)

func (s *Service) Upload(ctx *gin.Context) (interface{}, error) {
	file, fileHeader, err := ctx.Request.FormFile("file")
	if err != nil {
		return nil, err
	}

	url, err := uploadFile(file, fileHeader)
	if err != nil {
		return nil, errors.Wrap(err, "upload file failure")
	}

	return struct {
		Value string `json:"value"`
	}{
		Value: url,
	}, nil
}

func uploadFile(file multipart.File, fileHeader *multipart.FileHeader) (string, error) {
	fileName := uuid.New().String()
	ext := path.Ext(fileHeader.Filename)
	fileName = fileName + ext

	uploadSavePath := FileDir
	if checkSavePath(uploadSavePath) {
		if err := createSavePath(uploadSavePath, os.ModePerm); err != nil {
			return "", errors.New("failed to create save directory.")
		}
	}
	if checkPermission(uploadSavePath) {
		return "", errors.New("insufficient file permissions.")
	}

	dst := uploadSavePath + "/" + fileName
	if err := saveFile(fileHeader, dst); err != nil {
		return "", err
	}

	accessUrl := sys.UploadLinkPrefix + "/" + fileName
	return accessUrl, nil
}

func checkSavePath(dst string) bool {
	_, err := os.Stat(dst)
	return os.IsNotExist(err)
}

func checkPermission(dst string) bool {
	_, err := os.Stat(dst)
	return os.IsPermission(err)
}

func createSavePath(dst string, perm os.FileMode) error {
	err := os.MkdirAll(dst, perm)
	if err != nil {
		return err
	}

	return nil
}

func saveFile(file *multipart.FileHeader, dst string) error {
	src, err := file.Open()
	if err != nil {
		return err
	}
	defer src.Close()

	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, src)
	return err
}
